/*
 * Package il.ac.biu.cs.grossmm.api_tests.data
 * File PublicationPointTest.java
 * Created on Sep 8, 2006
 *
 */
package il.ac.biu.cs.grossmm.junit_api_tests.data;

import static il.ac.biu.cs.grossmm.api.data.NodeTypeByInterface.*;
import static il.ac.biu.cs.grossmm.api.keys.KeyFactory.*;
import static il.ac.biu.cs.grossmm.api.keys.PatternFactory.*;
import static il.ac.biu.cs.grossmm.api.presence.BaseVocabulary.*;
import static org.junit.Assert.*;
import il.ac.biu.cs.grossmm.api.OperationFailedException;
import il.ac.biu.cs.grossmm.api.data.*;
import il.ac.biu.cs.grossmm.api.flow.ActiveDataManager;
import il.ac.biu.cs.grossmm.api.flow.NodeExistsException;
import il.ac.biu.cs.grossmm.api.flow.NodeManipulator;
import il.ac.biu.cs.grossmm.api.flow.PersistentPointManager;
import il.ac.biu.cs.grossmm.api.flow.PublicationPoint;
import il.ac.biu.cs.grossmm.api.keys.Key;
import il.ac.biu.cs.grossmm.api.keys.KeyPattern;
import il.ac.biu.cs.grossmm.api.presence.ResourceType;
import il.ac.biu.cs.grossmm.api.presence.Pidf;
import il.ac.biu.cs.grossmm.api.presence.PidfTuple;
import il.ac.biu.cs.grossmm.api.server.Component;
import il.ac.biu.cs.grossmm.api.server.ComponentManager;
import il.ac.biu.cs.grossmm.api.server.ServiceManager;
import il.ac.biu.cs.grossmm.api.sql.SqlDataSource;
import il.ac.biu.cs.grossmm.impl.activeData.ActiveDataManagerImpl;
import il.ac.biu.cs.grossmm.impl.activeData.SqlPointManager;
import il.ac.biu.cs.grossmm.impl.hsqldb.DataSourceAdapter;
import il.ac.biu.cs.grossmm.impl.server.RegistryServer;
import il.ac.biu.cs.grossmm.api.server.Service;

import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class PublicationPointTest implements Component, Service {

	RegistryServer server = new RegistryServer();
	
	ActiveDataManager adm;
	
	ServiceManager sm;
	
	PublicationPoint<Pidf> pp1, pp2;
	
	@Before
	public void startUp() throws Exception {
		server.register(ActiveDataManager.class, new ActiveDataManagerImpl());
		server.register(PersistentPointManager.class, new SqlPointManager());
		server.register(SqlDataSource.class, 
                new DataSourceAdapter("jdbc:hsqldb:file:testpres_db", "sa", ""));
		
		server.register(ActiveDataManagerTest.class, this);
		server.addToStartup(ActiveDataManagerTest.class);
		
		server.start();
		
		assert adm != null;
		
		adm.removePublicationPoint("foo");
		adm.removePublicationPoint("bar");
		
		KeyPattern pattern1 = pattern(String.class, 
			mandatory(WATCHER, String.class),
			mandatory(RESOURCE_TYPE, ResourceType.PRESENCE)
			);
		
		KeyPattern pattern2 = pattern(String.class, 
			mandatory(RESOURCE_TYPE, ResourceType.WINFO)
			);
		
		pp1 = 
			adm.createPublicationPoint(pattern1, nodeType(Pidf.class), false, "foo");
		
		pp1 = 
			adm.createPublicationPoint(pattern2, nodeType(Pidf.class), false, "bar");
	}
	
	@After
	public void tearDown()
	{
		server.stop();
	}

	public void start(ServiceManager serviceManager) throws Exception
	{
		sm = serviceManager;
		System.out.println("TEST STARTED");
	}

	public void stop(Exception exception)
	{
		System.out.println("TEST STOPPED "+exception);
	}

	public void terminated(Object serviceHint, Exception e)
	{
		System.out.println("TERMINATED "+serviceHint+" : "+e);
		sm.terminated(e);
	}

	public void aborted(Object hint, Exception e)
	{
		System.out.println("ABORTED "+hint+" : "+e);
	}

	public void setComponentManager(ComponentManager container) throws Exception
	{
		 adm = (ActiveDataManager) container.getComponent(ActiveDataManager.class);
	}
	
	
	@Test
	public void testCreateAndDelete() throws NodeExistsException, OperationFailedException
	{
		Key key = key("Alice", 
			entry(WATCHER, "Bob"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Root<Pidf> pidf = pp1.createNode(key, false);
		
	
		try {
			pp1.createNode(key, false);
			
			fail("Created the same node twice");
		} catch( OperationFailedException e) {
			e.printStackTrace();
		}
		
		Root<Pidf> pidf2 = pp1.createNode(key, true);

		assertEquals(pidf, pidf2);
		
		pp1.deleteNode(key);
		pp1.createNode(key, false);
		pp1.deleteNode(key);
	}

	@Test
	public void testGetNode() throws NodeExistsException, OperationFailedException
	{
		Key key1 = key("Alice1", 
			entry(WATCHER, "Bob1"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Key key2 = key("Alice2", 
			entry(WATCHER, "Bob"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Key key3 = key("Alice3", 
			entry(WATCHER, "Carol"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Key key4 = key("Alice4", 
			entry(WATCHER, "Carol"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Key key5 = key("Alice5", 
			entry(WATCHER, "Carol"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Root<Pidf> pidf1 = pp1.createNode(key1, false);
		Root<Pidf> pidf2 = pp1.createNode(key2, false);
		Root<Pidf> pidf3 = pp1.createNode(key3, false);
		Root<Pidf> pidf4 = pp1.createNode(key4, false);
		
		assertFalse(pidf1.equals(pidf2));
		assertFalse(pidf1.equals(pidf3));
		assertFalse(pidf2.equals(pidf4));
		
		Root<Pidf> pidf1got = pp1.getRoot(key1);
		Root<Pidf> pidf4got = pp1.getRoot(key4);
		Root<Pidf> pidf2got = pp1.getRoot(key2);
		Root<Pidf> pidf3got = pp1.getRoot(key3);
		
		assertEquals(pidf1, pidf1got);
		assertEquals(pidf2, pidf2got);
		assertEquals(pidf3, pidf3got);
		assertEquals(pidf4, pidf4got);
		
		Root<Pidf> none = pp1.getRoot(key5);
		assertNull(none);
		
		pp1.deleteNode(key3);
		
		none = pp1.getRoot(key3);
		assertNull(none);
		
		pp1.deleteNode(key1);
		pp1.deleteNode(key2);
		pp1.deleteNode(key4);
		
		none = pp1.getRoot(key1);
		assertNull(none);
		
		none = pp1.getRoot(key4);
		assertNull(none);
	}


	@Test
	public void testManipulate1() throws NodeExistsException, OperationFailedException
	{
		Key key = key("Alice", 
			entry(WATCHER, "Bob"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Root<Pidf> pidf = pp1.createNode(key, false);
		
		assertTrue( "createNode returned null", pidf != null);
		
		NodeManipulator man =  pp1.writeLock(pidf);
		
		Set<Node<PidfTuple>> tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		
		assertTrue(tuples.isEmpty());
		
		man.setValue(pidf, Pidf.ENTITY, "Alice");
		String e = man.getValue(pidf, Pidf.ENTITY);
		
		assertEquals("Alice", e);
		
		man.setValue(pidf, Pidf.ENTITY, "Bob");
		e = man.getValue(pidf, Pidf.ENTITY);
		
		assertEquals("Bob", e);
		
		pp1.writeUnlock(pidf);
		
		man = pp1.writeLock(pidf);
		e = man.getValue(pidf, Pidf.ENTITY);
		pp1.writeUnlock(pidf);
		
		assertEquals("Bob", e);
		
		pp1.deleteNode(key);
	}

	@Test
	public void testManipulate2() throws NodeExistsException, OperationFailedException
	{
		Key key = key("Alice", 
			entry(WATCHER, "Bob"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Root<Pidf> pidf = pp1.createNode(key, false);
		
		NodeManipulator man =  pp1.writeLock(pidf);
		
		Node<PidfTuple> tuple1 = man.createSubnode(pidf, Pidf.TUPLES);
		Node<PidfTuple> tuple2 = man.createSubnode(pidf, Pidf.TUPLES);
		
		Set<Node<PidfTuple>> tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		
		assertEquals(2, tuples.size());
		assertTrue(tuples.contains(tuple1));
		assertTrue(tuples.contains(tuple2));
		
		man.setValue(tuple1, PidfTuple.ID, "123");
		man.setValue(tuple2, PidfTuple.ID, "234");
		
		String id1 = man.getValue(tuple1, PidfTuple.ID);
		String id2 = man.getValue(tuple2, PidfTuple.ID);
		
		assertEquals("123", id1);
		assertEquals("234", id2);
		
		String contact = man.getValue(tuple1, PidfTuple.CONTACT);
		
		assertNull(contact);
		
		man.removeSubnode(tuple1);
		tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		assertEquals(1, tuples.size());
		
		man.removeSubnode(tuple1);
		tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		assertEquals(1, tuples.size());
		
		man.removeSubnode(tuple2);
		tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		assertEquals(0, tuples.size());
		
		pp1.writeUnlock(pidf);
		
		pp1.deleteNode(key);
	}
	
	@Test
	public void testManipulate3() throws NodeExistsException, OperationFailedException
	{
		Key key = key("Alice", 
			entry(WATCHER, "Bob"),
			entry(RESOURCE_TYPE, ResourceType.PRESENCE));
		
		Root<Pidf> pidf = pp1.createNode(key, false);
		
		NodeManipulator man =  pp1.writeLock(pidf);
		
		Node<PidfTuple> tuple1 = man.createSubnode(pidf, Pidf.TUPLES);
		Node<PidfTuple> tuple2 = man.createSubnode(pidf, Pidf.TUPLES);
		
		Set<Node<PidfTuple>> tuples = man.getSubnodes(pidf, Pidf.TUPLES);
		
		assertEquals(2, tuples.size());
		assertTrue(tuples.contains(tuple1));
		assertTrue(tuples.contains(tuple2));
		
		man.setValue(tuple1, PidfTuple.ID, "123");
		
		try {
			man.setValue(tuple2, PidfTuple.ID, "123");
			
			fail();
		} catch( OperationFailedException expected ) {
			// ok
		}
		
		man.setValue(tuple2, PidfTuple.ID, "234");
		
		try {
			man.setValue(tuple1, PidfTuple.ID, "234");
			
			fail();
		} catch( OperationFailedException expected ) {
			// ok
		}
		
		man.setValue(tuple2, PidfTuple.ID, "234");
		
		Node<PidfTuple> tuple3 = man.getSubnode(pidf, Pidf.TUPLES, PidfTuple.ID, "123");
		
		assertEquals(tuple1, tuple3);
		
		pp1.writeUnlock(pidf);
		
		pp1.deleteNode(key);
	}
}
